/*
 * AXKeypadDispatcher.cpp
 *
 *  Created on: 2014年5月17日
 *      Author: coldwinter
 */

#include "AXKeypadDispatcher.h"
#include "AXKeypadDelegate.h"
#include <stdlib.h>
#include <string.h>

AXKeypadDispatcher::AXKeypadDispatcher():
CCObject(),
m_added(NULL),
m_removed(NULL),
m_block(false)
{
	memset(keymap,0,sizeof(keymap));
	m_key_handler = new CCArray();
    m_added = new CCArray();
    m_removed = new CCArray();
    
    m_handler = AXHandler::create();
    m_handler->setCallback(this,
       selector_handler(AXKeypadDispatcher::handleMessage));
}

AXKeypadDispatcher* AXKeypadDispatcher::sharedKeypadDispatcher()
{
    if(!g_instance)
    {
        g_instance = new AXKeypadDispatcher();
    }
    return g_instance;
}

void AXKeypadDispatcher::destroy()
{
    if(m_handler)
    {
        m_handler->cleanup();
        m_handler->release();
        m_handler = NULL;
    }
    this->release();
    
}

char AXKeypadDispatcher::keymap[256];
AXKeypadDispatcher* AXKeypadDispatcher::g_instance = NULL;

AXKeypadDispatcher::~AXKeypadDispatcher()
{
	CC_SAFE_RELEASE_NULL(m_key_handler);
    CC_SAFE_RELEASE_NULL(m_added);
    CC_SAFE_RELEASE_NULL(m_removed);
}

void AXKeypadDispatcher::registKeypadDispatcher(
                            AXKeypadDelegate* del)
{
	if(m_block)
	{
		if(m_added)
		{
            int index = getIndexInArray(m_removed, del);
            if(index >= 0)
            {
                m_removed->removeObjectAtIndex(index);
            }
            m_added->addObject(
                   AXKeypadHandler::createWithDelegate(del)
                               );
		}
	}
	else
	{
		m_key_handler->addObject(
			AXKeypadHandler::createWithDelegate(del)
			);
        CCLOG("add keypad delegate %x,left %d",(int) del,m_key_handler->count());
	}
}

void AXKeypadDispatcher::unregistKeypadDispatcher(AXKeypadDelegate* del)
{
	if(m_block)
	{
        if(m_removed)
        {
            int index = getIndexInArray(m_added, del);
            if(index >= 0)
            {
                m_added->removeObjectAtIndex(index);
            }
            else
            {
                m_removed->addObject(
                     AXKeypadHandler::createWithDelegate(del)
                                     );
            }
        }
	}
	else
	{
        int index = getIndexInArray(m_key_handler,del);
        if(index >= 0)
        {
            m_key_handler->removeObjectAtIndex(index);
            CCLOG("remove keypad delegate %x,left %d",(int) del,m_key_handler->count());
        }
	}
}

void AXKeypadDispatcher::handleKeypadMSG(int keyCode, int action)
{
    CCLOG("xd keypad message arrived keycode: %d,action:%d",keyCode,action);
	if(keyCode < 0 || keyCode > 255)
	{
		CCLOG("xd keyCode is out ouf bound : %d",keyCode);
		return;
	}
	if(action != 0)
	{
		action = 1;
	}
	m_block = true;
	int count = m_key_handler->count();
	for(int i = count - 1; i >= 0; i++)
	{
		AXKeypadHandler* handler = (AXKeypadHandler*)m_key_handler->data->arr[i];
		AXKeypadDelegate* del = handler->getDelegate();
		bool bFlag = false;
		switch(action)
		{
			case kAXKeyDown:
			{
				if(keymap[keyCode] == 0)
				{
					keymap[keyCode] = 1;
					bFlag = del->onKeyDown(keyCode);
				}
				else
				{
					bFlag = true;
				}
				break;
			}
			case kAXKeyUp:
			{
                if(keymap[keyCode])
                {
                    keymap[keyCode] = 0;
                    bFlag = del->onKeyUp(keyCode);
                }
                else
                {
                    bFlag = true;
                }
				break;
			}
		}
		CC_BREAK_IF(bFlag);
	}
CCLOG(",left %d",m_key_handler->count());
	if(m_added)
	{
		CCObject* obj;
		CCARRAY_FOREACH(m_added,obj)
		{
			AXKeypadHandler* handler = (AXKeypadHandler*)obj;

			if(getIndexInArray(m_key_handler, handler->getDelegate()) < 0)
			{
				m_key_handler->addObject(handler);
                CCLOG("add keypad delegate %x, left: %d",(int) handler->getDelegate(),m_key_handler->count());
			}
		}
		m_added->removeAllObjects();
	}
	if(m_removed)
	{
		CCObject* obj;
		CCARRAY_FOREACH(m_removed,obj)
		{
			AXKeypadHandler* handler = (AXKeypadHandler*)obj;
			int index = getIndexInArray(m_key_handler, handler->getDelegate());
			if( index >= 0)
			{
				m_key_handler->removeObjectAtIndex(index);
                CCLOG("remove keypad delegate %x,left %d",(int) handler->getDelegate(),m_key_handler->count());
			}
		}
		m_removed->removeAllObjects();
	}
}

int AXKeypadDispatcher::getIndexInArray(CCArray* arr,AXKeypadDelegate* del)
{
    if(del == NULL) return -1;
	int count = arr->count();
	for(int i = 0 ; i < count; i++)
	{
		AXKeypadHandler* handler = (AXKeypadHandler*)arr->data->arr[i];
		if(del == handler->getDelegate() )
		{
			return i;
		}
	}
	return -1;
}

void AXKeypadDispatcher::handleMessage(Message msg)
{
    CCLOG("recv key event keycode is : %d",msg.arg1);
    handleKeypadMSG(msg.arg1, msg.arg2);
}

void AXKeypadDispatcher::postKeyEvent(int keyCode, int action)
{
    if(m_handler)
    {
        Message msg;
        msg.arg1 = keyCode;
        msg.arg2 = action;
        m_handler->postMessage(msg);
    }
}

